home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / Peter Lewis (TCPExample) / PNL Libraries / MyTransport.p < prev    next >
Encoding:
Text File  |  1996-01-11  |  51.1 KB  |  1,987 lines  |  [TEXT/CWIE]

  1. unit MyTransport;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types, OpenTransport, TCPTypes, TCPUtils;
  7.     
  8.     var
  9.         have_OT:Boolean;
  10.  
  11.     const
  12.         couldNotGetRequestedPortErr = -99;
  13.             
  14.     const
  15.         kMyStreamClosingErr = connectionClosingErr;
  16.     
  17.     type
  18.         TransportDeferredTaskCookie = longint;
  19.         TransportDeferredTaskProcPtr = ProcPtr; { procedure(arg:ptr) }
  20.         TransportRef = ^integer;
  21.         TransportUDPRef = ^point;
  22.     
  23.     type
  24.         IPAddrArray = array[1..1000] of IPAddr;
  25.         IPAddrArrayPtr = ^IPAddrArray;
  26.  
  27.     type
  28.         MemoryReleasedProc = procedure (tref: TransportRef; result: OTResult; cookie: univ Ptr);
  29.  
  30.     var
  31.         hack_MemoryReleasedProc: MemoryReleasedProc;
  32. { * means Interupt-safe }
  33.  
  34.     procedure StartupTransport;
  35.     procedure ConfigureTransport(allow_OT: Boolean);
  36.     
  37.     function OpenTransportSystem:OSStatus;
  38.     procedure CloseTransportSystem;
  39.  
  40.     function TransportUDPOpenPort(var tref: TransportUDPRef; var localport: integer; buffer_size:longint): OSStatus;
  41.     procedure TransportUDPDestroy (var tref: TransportUDPRef);
  42.     function TransportUDPDatagramsAvailable (tref: TransportUDPRef): longint;
  43.     function TransportUDPRead (tref: TransportUDPRef; var remoteIP: longint; var remoteport: integer;
  44.                                     var datap: ptr; var datalen: integer): OSStatus;
  45.     function TransportUDPReturnBuffer (tref: TransportUDPRef; datap: ptr): OSStatus;
  46.     function TransportUDPWrite (tref: TransportUDPRef; remoteIP: longint; remoteport: integer;
  47.                                     datap: ptr; datalen: integer; checksum: boolean): OSStatus;
  48.     
  49.     function TransportListen(var token:Ptr; localport:integer; listeners:integer; buffer_size:longint):OSStatus;
  50.     function TransportGetListenerConnection(token:Ptr; var tref:TransportRef):OSStatus;
  51.     procedure TransportDestroyListener(var token:Ptr);
  52.  
  53.     function TransportOpenActiveConnection(var tref:TransportRef; dest:Str255; localport:integer; buffer_size:longint): OSStatus;
  54.     function TransportOpenPassiveConnection(var tref:TransportRef; var localport:integer; buffer_size:longint): OSStatus;
  55.     procedure TransportGetOpenResult(tref:TransportRef; var result: OSStatus); { * }
  56.     
  57.     procedure TransportDestroy(var tref:TransportRef);
  58.  
  59.     function TransportGetConnectionState (tref:TransportRef): TCPStateType;
  60.     function TransportGetConnectionStateInteruptSafe (tref:TransportRef): TCPStateType; { * }
  61.         { Note: May not change until idle time }
  62.     function TransportGetPorts(tref:TransportRef; var localip: IPAddr; var localport: integer; var remoteip: longint; var remoteport: integer): OSStatus;
  63.     procedure TransportSendClose(tref:TransportRef);
  64.  
  65.     function TransportHandleTransfers(tref:TransportRef): OSStatus;
  66.  
  67.     function TransportHandleReceives(tref:TransportRef): OSStatus;
  68.     function TransportReceive(tref:TransportRef; buf: Ptr; len:longint; var count:longint): OSStatus;
  69.     function TransportCharsAvailable(tref:TransportRef): longint;
  70.  
  71.     function TransportHandleSends(tref:TransportRef): OSStatus;
  72.     function TransportSend(tref:TransportRef; buf: Ptr; len:longint): OSStatus;
  73.     
  74.     procedure TransportLowGetStreamPtr(tref:TransportRef; var stream: StreamPtr);
  75.     procedure TransportLowGetEndpointRef(tref:TransportRef; var ep: EndpointRef);
  76.     function TransportLowSetOTAckSends(tref:TransportRef; handler: MemoryReleasedProc): OSStatus;
  77.     
  78.     function TransportGetMyIPAddr(var ip:IPAddr): OSStatus;
  79.     
  80.     function TransportCreateDeferredTask(proc: OTProcessProcPtr; arg: UNIV Ptr): TransportDeferredTaskCookie;
  81.     procedure ScheduleDeferredTask(cookie:TransportDeferredTaskCookie); { * }
  82.     procedure DestroyDeferredTaskCookie(cookie:TransportDeferredTaskCookie);
  83.  
  84.     procedure TransportEnterInterrupt;
  85.     procedure TransportLeaveInterrupt;
  86.     
  87.     function TransportNameToAddr(name: Str255; var token: Ptr): OSStatus;
  88.     procedure TransportGetNameToAddrResult(var token: Ptr; var result: OSStatus; name:StringPtr; addrs:IPAddrArrayPtr; len:integer); { * }
  89.  
  90.     function TransportAddrToName(addr: IPAddr; var token: Ptr): OSStatus;
  91.     procedure TransportGetAddrToNameResult(var token: Ptr; var result: OSStatus; var name:Str255); { * }
  92.  
  93.     procedure TransportAbortDNR(var token: Ptr);
  94.  
  95.     function StringToIPAddr (s: Str255; var addr: longInt): boolean;
  96.     procedure IPAddrToString (ip: longInt; var addrStr: Str255);
  97.     function IPAddrToStr (ip: longInt): Str255;
  98.     procedure IPAddrPortToString (ip: longInt; port: integer; var addrStr: Str255);
  99.     function IPAddrPortToStr (ip: longInt; port: integer): Str255;
  100.  
  101. implementation
  102.  
  103.     uses
  104.         Events, TextUtils, Processes, OSUtils,Memory, 
  105.         OpenTptInternet, GestaltEqu, Devices, CodeFragments, MixedMode, 
  106.         MyCStrings, MyAssertions, DNR, MyStrings, MyMathUtils, MyGrowZones, MyTypes, 
  107.         MyUtils, MyMemory, MyCallProc, QLowLevel, PreserveA5, MyStartup;
  108.  
  109.     const
  110.         use_OT_tasks = false;
  111.     
  112.     type
  113.         TransportUDPRecord = record
  114.             case boolean of
  115.             false:(
  116.                 stream: StreamPtr;
  117.                 stream_buffer: Ptr;
  118.                 outstanding_packets: longint;
  119.             )
  120.             true:(
  121.                 ep: EndpointRef;
  122.                 received_packets, read_packets: longint;
  123.             )
  124.         end;
  125.         TransportUDPRecordPtr = ^TransportUDPRecord;
  126.         
  127.     type
  128.         TransportRecordPtr = ^TransportRecord;
  129.         TransportRecord = record
  130.             next: TransportRecordPtr;
  131.             input_handle: Handle;
  132.             output_handle: Handle;
  133.             sending_handle: Handle;
  134.             send_error, receive_error: OSStatus;
  135.             open_result: OSStatus;
  136.             started_opening: Boolean;
  137.             handle_receives, handle_sends: Boolean;
  138.             do_send_close: Boolean;
  139.             case boolean of
  140.             false:(
  141.                 remote_port:integer;
  142.                 local_port:integer;
  143.                 stream:StreamPtr;
  144.                 stream_buffer:Ptr;
  145.                 open_cb, close_cb, send_cb:TCPControlBlock;
  146.                 send_wds: wdsType;
  147.                 dnr_token:Ptr;
  148.                 tstate:TCPStateType;
  149.             )
  150.             true:(
  151.                 ep: EndpointRef;
  152.                 rcvCall, sndCall: TCall;
  153.                 rcvsin: InetAddress;
  154.                 sndsin: DNSAddress;
  155.                 waiting_for_connect: Boolean;
  156.                 connect_received: Boolean;
  157.                 accept_received: Boolean;
  158.                 passcon_received: Boolean;
  159.                 wake_process:ProcessSerialNumber;
  160.                 disconnect_received: Boolean;
  161.                 getprotaddr_result: OSStatus;
  162.                 connect_result:OSStatus;
  163.                 accept_result:OSStatus;
  164.                 passcon_result:OSStatus;
  165.                 MemoryReleasedHandler: MemoryReleasedProc;
  166.             )
  167.         end;
  168.  
  169.     type
  170.         MyDeferredTask = record
  171.             dt:DeferredTask;
  172.             fired:Boolean;
  173.             completion:UniversalProcPtr;
  174.             real_arg:longint;
  175.         end;
  176.         MyDeferredTaskPtr = ^MyDeferredTask;
  177.     
  178.     type
  179.         XInetHostInfo = record
  180.             host:InetHostInfo;
  181.             result:OSStatus;
  182.         end;
  183.         XInetHostInfoPtr = ^XInetHostInfo;
  184.         TDNRRecordPtr = ^TDNRRecord;
  185.         TDNRRecord = record
  186.             next:TDNRRecordPtr;
  187.             kind: (TK_NameToAddr, TK_AddrToName);
  188.             dead: Boolean;
  189.             case boolean of
  190.                 true:(
  191.                     dr:DNRRecord;
  192.                     canonical_name: Str255;
  193.                 );
  194.                 false:(
  195.                     xhost:XInetHostInfo; { Warning InetHostInfo must *start* with an InetDomainName! }
  196.                 );
  197.         end;
  198.         
  199.     var
  200.         transports:QHdr;
  201.         gMyDeferredTaskHandlerProc : UniversalProcPtr;
  202.         tcp_is_open:Boolean;
  203.         is_ref:InetSvcRef;
  204.         is_result: OTResult;
  205.         dnrs:QHdr;
  206.         
  207.     procedure InternetServicesHandler(context:Ptr; event: OTEventCode; result: OTResult; cookie: XInetHostInfoPtr);
  208.     begin
  209.         context := context; { UNUSED! }
  210.         case event of
  211.             T_OPENCOMPLETE: begin
  212.                 is_ref := InetSvcRef(cookie);
  213.                 is_result := result;
  214.             end;
  215.             T_DNRSTRINGTOADDRCOMPLETE, T_DNRADDRTONAMECOMPLETE: begin
  216.                 cookie^.result := result;
  217.             end;
  218.             otherwise
  219.                 ;
  220.         end;
  221.     end;
  222.  
  223.     function WaitForInternetServices: OSStatus;
  224.     begin
  225.         while is_result = inProgress do begin
  226.         end;
  227.         WaitForInternetServices := is_result;
  228.     end;
  229.     
  230.     function ValidDNR(token: Ptr): Boolean;
  231.         var
  232.             this:TDNRRecordPtr;
  233.     begin
  234.         ValidDNR := false;
  235.         this := TDNRRecordPtr(dnrs.qHead);
  236.         while this <> nil do begin
  237.             if Ptr(this) = token then begin
  238.                 ValidDNR := true;
  239.                 leave;
  240.             end;
  241.             this := this^.next;
  242.         end;
  243.     end;
  244.     
  245.     function TransportNameToAddr(name: Str255; var token: Ptr): OSStatus;
  246.         var
  247.             err: OSStatus;
  248.             tdrp:TDNRRecordPtr;
  249.     begin
  250.         tdrp := nil;
  251.         err := OpenTransportSystem;
  252.         if err = noErr then begin
  253.             err := MNewPtr(tdrp, SizeOf(TDNRRecord));
  254.         end;
  255.         if err = noErr then begin
  256.             tdrp^.kind := TK_NameToAddr;
  257.             tdrp^.dead := false;
  258.             if have_OT then begin
  259.                 tdrp^.xhost.result := inProgress;
  260.                 P2C(@name);
  261.                 err := WaitForInternetServices;
  262.                 if err = noErr then begin
  263.                     err := OTInetStringToAddress(is_ref, @name, tdrp^.xhost.host);
  264.                 end;
  265.             end else begin
  266.                 tdrp^.canonical_name := name;
  267.                 DNRNameToAddr(name, @tdrp^.dr, nil);
  268.                 err := noErr;
  269.             end;
  270.         end;
  271.         if err = noErr then begin
  272.             Enqueue(QElemPtr(tdrp),@dnrs);
  273.         end else begin
  274.             MDisposePtr(tdrp);
  275.         end;
  276.         token := Ptr(tdrp);
  277.         TransportNameToAddr := err;
  278.     end;
  279.     
  280.     procedure TransportGetNameToAddrResult(var token: Ptr; var result: OSStatus; name:StringPtr; addrs:IPAddrArrayPtr; len:integer);
  281.         var
  282.             tdrp:TDNRRecordPtr;
  283.             i:integer;
  284.             junk: OSStatus;
  285.     begin
  286.         tdrp := TDNRRecordPtr(token);
  287.         result := -1;
  288.         if (tdrp <> nil) then begin
  289.             if not ValidDNR(token) then begin
  290.                 DebugStr('Invalid DNR Token;sc');
  291.             end else begin
  292.                 if have_OT then begin
  293.                     result := tdrp^.xhost.result;
  294.                     if result = noErr then begin
  295.                         if name <> nil then begin
  296.                             CopyC2P(@tdrp^.xhost.host.name, name^);
  297.                         end;
  298.                         for i := 1 to len do begin
  299.                             addrs^[i] := 0;
  300.                         end;
  301.                         for i := 1 to Min(kMaxHostAddrs, len) do begin
  302.                             addrs^[i] := tdrp^.xhost.host.addrs[i-1];
  303.                         end;
  304.                     end;
  305.                 end else begin
  306.                     result := tdrp^.dr.ioResult;
  307.                     if result = noErr then begin
  308.                         if name <> nil then begin
  309.                             name^ := tdrp^.canonical_name;
  310.                         end;
  311.                         for i := 1 to len do begin
  312.                             addrs^[i] := 0;
  313.                         end;
  314.                         for i := 1 to Min(len, 4) do begin
  315.                             addrs^[i] := tdrp^.dr.hi.addrs[i];
  316.                         end;
  317.                     end;
  318.                 end;
  319.                 if result <> inProgress then begin
  320.                     junk := Dequeue(QElemPtr(tdrp),@dnrs);
  321.                     MDisposePtr(tdrp);
  322.                     token := nil;
  323.                 end;
  324.             end;
  325.         end;
  326.     end;
  327.     
  328.     function TransportAddrToName(addr: IPAddr; var token: Ptr): OSStatus;
  329.         var
  330.             err: OSStatus;
  331.             tdrp:TDNRRecordPtr;
  332.     begin
  333.         tdrp := nil;
  334.         err := OpenTransportSystem;
  335.         if err = noErr then begin
  336.             err := MNewPtr(tdrp, SizeOf(TDNRRecord));
  337.         end;
  338.         if err = noErr then begin
  339.             tdrp^.kind := TK_AddrToName;
  340.             tdrp^.dead := false;
  341.             if have_OT then begin
  342.                 tdrp^.xhost.result := inProgress;
  343.                 err := WaitForInternetServices;
  344.                 if err = noErr then begin
  345.                     err := OTInetAddressToName(is_ref, addr, tdrp^.xhost.host.name);
  346.                 end;
  347.             end else begin
  348.                 DNRAddrToName(addr, @tdrp^.dr, nil);
  349.                 err := noErr;
  350.             end;
  351.         end;
  352.         if err = noErr then begin
  353.             Enqueue(QElemPtr(tdrp),@dnrs);
  354.         end else begin
  355.             MDisposePtr(tdrp);
  356.         end;
  357.         token := Ptr(tdrp);
  358.         TransportAddrToName := err;
  359.     end;
  360.     
  361.     procedure TransportGetAddrToNameResult(var token: Ptr; var result: OSStatus; var name:Str255);
  362.         var
  363.             tdrp:TDNRRecordPtr;
  364.             junk: OSStatus;
  365.     begin
  366.         tdrp := TDNRRecordPtr(token);
  367.         result := -1;
  368.         if tdrp <> nil then begin
  369.             if not ValidDNR(token) then begin
  370.                 DebugStr('Invalid DNR Token;sc');
  371.             end else begin
  372.                 if have_OT then begin
  373.                     result := tdrp^.xhost.result;
  374.                     if result = noErr then begin
  375.                         CopyC2P(@tdrp^.xhost.host.name, name);
  376.                     end;
  377.                 end else begin
  378.                     result := tdrp^.dr.ioResult;
  379.                     if result = noErr then begin
  380.                         name := tdrp^.dr.name;
  381.                     end;
  382.                 end;
  383.                 if result <> inProgress then begin
  384.                     junk := Dequeue(QElemPtr(tdrp),@dnrs);
  385.                     MDisposePtr(tdrp);
  386.                     token := nil;
  387.                 end;
  388.             end;
  389.         end;
  390.         if (result = noErr) & (name[length(name)] = '.') then begin
  391.             Delete(name, length(name), 1);
  392.         end;
  393.     end;
  394.     
  395.     procedure TransportAbortDNR(var token: Ptr);
  396.         var
  397.             tdrp:TDNRRecordPtr;
  398.     begin
  399.         if token <> nil then begin
  400.             if not ValidDNR(token) then begin
  401.                 DebugStr('Invalid DNR Token;sc');
  402.             end else begin
  403.                 tdrp := TDNRRecordPtr(token);
  404.                 tdrp^.dead := true;
  405.             end;
  406.         end;
  407.     end;
  408.  
  409.     procedure IdleDNR(this:TDNRRecordPtr);
  410.         var
  411.             result: OSStatus;
  412.             name:Str255;
  413.     begin
  414.         case this^.kind of
  415.             TK_NameToAddr: begin
  416.                 TransportGetNameToAddrResult(Ptr(this), result, nil, nil, 0);
  417.             end;
  418.             TK_AddrToName: begin
  419.                 TransportGetAddrToNameResult(Ptr(this), result, name);
  420.             end;
  421.         end;
  422.     end;
  423.     
  424.     procedure IdleDNRs;
  425.         var
  426.             this, next:TDNRRecordPtr;
  427.     begin
  428.         this := TDNRRecordPtr(dnrs.qHead);
  429.         while this <> nil do begin
  430.             next := this^.next;
  431.             if this^.dead then begin
  432.                 IdleDNR(this);
  433.             end;
  434.             this := next;
  435.         end;
  436.     end;
  437.     
  438.     function StringToIPAddr (s: Str255; var addr: longInt): boolean;
  439.         var
  440.             good: boolean;
  441.         procedure Get1;
  442.             var
  443.                 b: integer;
  444.         begin
  445.             if (length(s) = 0) | not (s[1] in ['0'..'9']) then begin
  446.                 good := false;
  447.             end else begin
  448.                 b := ord(s[1]) - 48;
  449.                 s := TPCopy(s, 2, 255);
  450.                 if (s <> '') & (s[1] in ['0'..'9']) then begin
  451.                     b := b * 10 + ord(s[1]) - 48;
  452.                     s := TPCopy(s, 2, 255);
  453.                 end;
  454.                 if (s <> '') & (s[1] in ['0'..'9']) then begin
  455.                     b := b * 10 + ord(s[1]) - 48;
  456.                     s := TPCopy(s, 2, 255);
  457.                 end;
  458.                 if (s <> '') & (s[1] = '.') then begin
  459.                     s := TPCopy(s, 2, 255);
  460.                 end;
  461.                 if b > 255 then begin
  462.                     good := false;
  463.                     b := 0; { avoid overflow error? }
  464.                 end;
  465.                 addr := BOR(BSL(addr, 8), b);
  466.             end;
  467.         end;
  468.     begin
  469.         good := true;
  470.         addr := 0;
  471.         Get1;
  472.         Get1;
  473.         Get1;
  474.         Get1;
  475.         good := good & (s = '');
  476.         if not good then begin
  477.             addr := 0;
  478.         end;
  479.         StringToIPAddr := good;
  480.     end;
  481.  
  482.     procedure IPAddrToString (ip: longInt; var addrStr: Str255);
  483.         function GetByte(ip: longint; bits: integer): Str255;
  484.             var
  485.                 t:Str255;
  486.         begin
  487.              NumToString(band(bsr(ip, bits), $00FF), t);
  488.              GetByte := t;
  489.         end;
  490.     begin
  491.         addrStr := GetByte(ip, 24);
  492.         addrStr := concat(addrStr, '.', GetByte(ip, 16));
  493.         addrStr := concat(addrStr, '.', GetByte(ip, 8));
  494.         addrStr := concat(addrStr, '.', GetByte(ip, 0));
  495.     end;
  496.  
  497.     function IPAddrToStr (ip: longInt): Str255;
  498.         var
  499.             s: Str255;
  500.     begin
  501.         IPAddrToString(ip, s);
  502.         IPAddrToStr := s;
  503.     end;
  504.  
  505.     procedure IPAddrPortToString (ip: longInt; port: integer; var addrStr: Str255);
  506.         var
  507.             ns:Str255;
  508.     begin
  509.         NumToString(band(port, $0000FFFF), ns);
  510.         addrStr := concat(IPAddrToStr(ip),':', ns);
  511.     end;
  512.     
  513.     function IPAddrPortToStr (ip: longInt; port: integer): Str255;
  514.         var
  515.             ns:Str255;
  516.     begin
  517.         NumToString(band(port, $0000FFFF), ns);
  518.         IPAddrPortToStr := concat(IPAddrToStr(ip),':', ns);
  519.     end;
  520.     
  521.     procedure WaitForDNRCompletions;
  522.         var
  523.             this:TDNRRecordPtr;
  524.     begin
  525.         if not have_OT then begin
  526.             while dnrs.qHead <> nil do begin
  527.                 this := TDNRRecordPtr(dnrs.qHead);
  528.                 IdleDNR(this);
  529.             end;
  530.         end;
  531.     end;
  532.     
  533. { Deferred Tasks }
  534.     
  535.     procedure MyDeferredTaskHandlerPascal(dtp: MyDeferredTaskPtr);
  536.         var
  537.             olda5:Ptr;
  538.     begin
  539.         olda5 := SetPreservedA5;
  540.         dtp^.fired := true;
  541.         CallPascal04(dtp^.real_arg, dtp^.completion);
  542.         RestoreA5(olda5);
  543.     end;
  544.  
  545. {$IFC GENERATINGPOWERPC}
  546.     procedure MyDeferredTaskHandler(dtp: MyDeferredTaskPtr);
  547.     begin
  548.         MyDeferredTaskHandlerPascal(dtp);
  549.     end;
  550. {$ELSEC}
  551.     procedure MyDeferredTaskHandler;
  552.         var
  553.             param:MyDeferredTaskPtr;
  554.     begin
  555.         param := MyDeferredTaskPtr(GetRegA1);
  556.         MyDeferredTaskHandlerPascal(param);
  557.     end;
  558. {$ENDC}
  559.  
  560.     function TransportCreateDeferredTask(proc: OTProcessProcPtr; arg: UNIV Ptr): TransportDeferredTaskCookie;
  561.         var
  562.             dtp:MyDeferredTaskPtr;
  563.             result:longint;
  564.     begin
  565.         result := 0;
  566.         if have_OT & use_OT_tasks then begin
  567.             if OpenTransportSystem = noErr then begin
  568.                 result := OTCreateDeferredTask(proc, arg);
  569.             end;
  570.         end else begin
  571.             dtp := MyDeferredTaskPtr(NewPtr(SizeOf(MyDeferredTask)));
  572.             if dtp <> nil then begin
  573.                 dtp^.dt.dtAddr := gMyDeferredTaskHandlerProc;
  574.                 dtp^.dt.dtParam := longint(dtp);
  575.                 dtp^.dt.dtReserved := 0;
  576.                 dtp^.dt.dtFlags := 0;
  577.                 dtp^.dt.qType := ord(dtQType);
  578.                 dtp^.completion := NewProc(proc, uppPascal04ProcInfo);
  579.                 dtp^.real_arg := longint(arg);
  580.                 dtp^.fired := true;
  581.                 result := TransportDeferredTaskCookie(dtp);
  582.             end;
  583.         end;
  584.         TransportCreateDeferredTask := result;
  585.     end;
  586.  
  587.     procedure ScheduleDeferredTask(cookie:TransportDeferredTaskCookie);
  588.         var
  589.             dummy:Boolean;
  590.             dtp:MyDeferredTaskPtr;
  591.     begin
  592.         if have_OT & use_OT_tasks then begin
  593.             dummy := OTScheduleDeferredTask(cookie);
  594.         end else begin
  595.             dtp := MyDeferredTaskPtr(cookie);
  596.             if dtp^.fired then begin
  597.                 if DTInstall(DeferredTaskPtr(dtp)) = noErr then begin
  598.                     dtp^.fired := false;
  599.                 end;
  600.             end;
  601.         end;
  602.     end;
  603.  
  604.     procedure DestroyDeferredTaskCookie(cookie:TransportDeferredTaskCookie);
  605.         var
  606.             junk:OSStatus;
  607.             dtp:MyDeferredTaskPtr;
  608.     begin
  609.         if have_OT & use_OT_tasks then begin
  610.             junk := OTDestroyDeferredTask(cookie);
  611.         end else begin
  612.             dtp := MyDeferredTaskPtr(cookie);
  613.             while not dtp^.fired do begin
  614.                 { wait til it fires since we can't abort it }
  615.             end;
  616.             DisposeRoutineDescriptor(dtp^.completion);
  617.             DisposePtr(Ptr(cookie));
  618.         end;
  619.     end;
  620.  
  621.     procedure TransportEnterInterrupt;
  622.     begin
  623.         if have_OT then begin
  624.             OTEnterInterrupt;
  625.         end;
  626.     end;
  627.     
  628.     procedure TransportLeaveInterrupt;
  629.     begin
  630.         if have_OT then begin
  631.             OTLeaveInterrupt;
  632.         end;
  633.     end;
  634.  
  635.     function OpenTransportSystemOT:OSStatus;
  636.         var
  637.             err: OSStatus;
  638.     begin
  639.         err :=     InitOpenTransport;
  640.         if err = noErr then begin
  641.             is_result := inProgress;
  642.             is_ref := nil;
  643.             err := OTAsyncOpenInternetServices(OTConfigurationPtr(kDefaultInternetServicesPath), 0, @InternetServicesHandler,nil);
  644.             if err <> noErr then begin
  645.                 is_result := err;
  646.             end;
  647.         end;
  648.         OpenTransportSystemOT := err;
  649.     end;
  650.     
  651.     procedure CloseTransportSystemOT;
  652.         var
  653.             junk:OSStatus;
  654.     begin
  655.         if is_ref <> nil then begin
  656.             junk := OTCloseProvider(is_ref);
  657.         end;
  658.         CloseOpenTransport;
  659.     end;
  660.     
  661.     function TransportGetConnectionStateOT(ep: EndpointRef):TCPStateType;
  662.         var
  663.             result: OTResult;
  664.             state:TCPStateType;
  665.     begin
  666.         result := OTGetEndpointState(ep);
  667.         state := T_Dead;
  668.         if result >= 0 then begin
  669.             case result of
  670.                 T_UNINIT, T_UNBND:
  671.                     state := T_Dead;
  672.                 T_IDLE:begin
  673.                     state := T_Bored;
  674.                 end;
  675.                 T_INCON, T_OUTCON:
  676.                     state := T_Opening;
  677.                 T_DATAXFER:
  678.                     state := T_Established;
  679.                 T_OUTREL:
  680.                     state := T_Closing;
  681.                 T_INREL:
  682.                     state := T_PleaseClose;
  683.                 otherwise begin
  684.                     state := T_Unknown;
  685.                 end;
  686.             end;
  687.         end;
  688.         TransportGetConnectionStateOT := state;
  689.     end;
  690.  
  691. { MacTCP routines }
  692.  
  693.     function OpenTransportSystemMT:OSStatus;
  694.         var
  695.             err:OSStatus;
  696.     begin
  697.         err := OpenDriver('.IPP', mactcp_driver_refnum);
  698.         if err = noErr then begin
  699.             err := OpenResolver;
  700.         end;
  701.         OpenTransportSystemMT :=     err;
  702.     end;
  703.     
  704.     procedure CloseTransportSystemMT;
  705.     begin
  706.         CloseResolver;
  707.     end;
  708.  
  709. { Generic routines }
  710.  
  711.     function OpenTransportSystem:OSStatus;
  712.         var
  713.             err:OSStatus;
  714.     begin
  715.         if tcp_is_open then begin
  716.             err := noErr;
  717.         end else if have_OT then begin
  718.             err := OpenTransportSystemOT;
  719.         end else begin
  720.             err := OpenTransportSystemMT;
  721.         end;
  722.         tcp_is_open := err = noErr;
  723.         OpenTransportSystem := err;
  724.     end;
  725.     
  726.     procedure CloseTransportSystem;
  727.     begin
  728.         if tcp_is_open then begin
  729.             if have_OT then begin
  730.                 CloseTransportSystemOT;
  731.             end else begin
  732.                 CloseTransportSystemMT;
  733.             end;
  734.         end;
  735.     end;
  736.  
  737.     function TransportGetMyIPAddr(var ip:IPAddr): OSStatus;
  738.         var
  739.             err: OSStatus;
  740.             cb: IPControlBlock;
  741.             info:InetInterfaceInfo;
  742.     begin
  743.         err := OpenTransportSystem;
  744.         if err = noErr then begin
  745.             if have_OT then begin
  746.                 err := OTInetGetInterfaceInfo(info, 0);
  747.                 ip := info.fAddress
  748.             end else begin
  749.                 MZero(@cb, SizeOf(cb));
  750.                 cb.ioCRefNum := mactcp_driver_refnum;
  751.                 cb.csCode := TCPcsGetMyIP;
  752.                 err := PBControlSync(@cb);
  753.                 ip := cb.getmyip.ourAddress;
  754.             end;
  755.         end;
  756.         TransportGetMyIPAddr := err;
  757.     end;
  758.     
  759. { Open }
  760.  
  761.     function CreateOTEndpoint(var ep:EndpointRef; proc:OTNotifyProcPtr; context:univ Ptr):OSErr;
  762.         var
  763.             err, junk: OSStatus;
  764.             config: Str255;
  765.             info: TEndpointInfo;
  766.     begin
  767.         config := 'tcp';
  768.         P2C(@config);
  769.         ep:=OTOpenEndpoint(OTCreateConfiguration(@config),0,info,err);
  770.         if err = noErr then begin
  771.             if proc <> nil then begin
  772.                 err:=OTInstallNotifier(ep, proc, context);
  773.             end;
  774.             if err <> noErr then begin
  775.                 junk := OTCloseProvider(ep);
  776.             end;
  777.         end;
  778.         CreateOTEndpoint := err;
  779.     end;
  780.     
  781.     procedure OTInitNetbuf(var nb:TNetbuf; buf:Ptr; len:size);
  782.     begin
  783.         nb.buf := buf;
  784.         nb.len := len;
  785.         nb.maxlen := len;
  786.     end;
  787.     
  788.     function SetReuseAddr(ep:EndpointRef):OSErr;
  789.         var
  790.             optreq:TOptMgmt;
  791.             optBuffer:record
  792.                 header:TOptionHeader;
  793.                 value:longint;
  794.             end;
  795.     begin
  796.         optreq.flags := T_NEGOTIATE;
  797.         OTInitNetbuf(optreq.opt, @optBuffer, kOTFourByteOptionSize);
  798.         optBuffer.header.len := kOTFourByteOptionSize;
  799.         optBuffer.header.level := INET_IP;
  800.         optBuffer.header.optName := IP_REUSEADDR;
  801.         optBuffer.header.status := 0;
  802.         optBuffer.value := $01000000;
  803.         SetReuseAddr := OTOptionManagement(ep, optreq, optreq);
  804.     end;
  805.  
  806.     function BindOTListener(ep:EndpointRef; var localport:integer; listeners:integer):OSErr;
  807.         var
  808.             err:OSStatus;
  809.             reqsin, retsin:InetAddress;
  810.             req, ret:TBind;
  811.     begin
  812.         MZero(@req, sizeof(req));
  813.         err := noErr;
  814.         if localport <> 0 then begin
  815.             err := SetReuseAddr(ep);
  816.             OTInitInetAddress(reqsin, localport, 0);
  817.             OTInitNetbuf(req.addr, @reqsin, sizeof(InetAddress));
  818.         end else begin
  819.             OTInitNetbuf(req.addr, nil, 0);
  820.         end;
  821.         req.qlen := listeners;
  822.         
  823.         MZero(@ret, sizeof(ret));
  824.         OTInitNetbuf(ret.addr, @retsin, sizeof(InetAddress));
  825.         
  826.         if err = noErr then begin
  827.             err := OTBind(ep, @req, @ret);
  828.             if (localport <> 0) & (localport <> retsin.fPort) then begin
  829.                 err := couldNotGetRequestedPortErr;
  830.             end;
  831.             localport := retsin.fPort;
  832.         end;
  833.         
  834.         if err = noErr then begin
  835.             err:=OTSetAsynchronous(ep);
  836.         end;
  837.         BindOTListener := err;
  838.     end;
  839.     
  840.     procedure EventHandlerOT (btp:TransportRecordPtr; event: OTEventCode; result: OTResult; cookie: univ Ptr);
  841.         var
  842.             junk:OSStatus;
  843.     begin
  844.         cookie := cookie; { UNUSED! }
  845.         case event of
  846.             T_OPENCOMPLETE: begin
  847.             end;
  848.             T_ACCEPTCOMPLETE:  begin
  849.                 btp^.accept_result := result;
  850.                 btp^.accept_received := true;
  851.             end;
  852.             T_PASSCON: begin
  853.                 btp^.passcon_result := result;
  854.                 btp^.passcon_received := true;
  855.             end;
  856.             T_CONNECT:  begin
  857.                 btp^.connect_result := result;
  858.                 btp^.connect_received := true;
  859.                 junk := OTRcvConnect(btp^.ep, btp^.rcvCall);
  860.             end;
  861.             T_DISCONNECT:  begin
  862.                 btp^.connect_result := result;
  863.                 btp^.disconnect_received := true;
  864.                 junk := OTRcvDisconnect( btp^.ep, nil ); 
  865.             end;
  866.             T_GETPROTADDRCOMPLETE: begin
  867.                 btp^.getprotaddr_result := result
  868.             end;
  869.             T_ORDREL:  begin
  870.                 junk := OTRcvOrderlyDisconnect( btp^.ep );
  871.             end;
  872.             T_DATA, T_GODATA: begin
  873.                 if (btp^.wake_process.highLongOfPSN <> 0) or (btp^.wake_process.lowLongOfPSN <> kNoProcess) then begin
  874.                     junk := WakeUpProcess(btp^.wake_process);
  875.                 end;
  876.             end;
  877.             T_DISCONNECTCOMPLETE: begin
  878.             end;
  879.             T_MEMORYRELEASED: begin
  880.                 if btp^.MemoryReleasedHandler <> nil then begin
  881.                     btp^.MemoryReleasedHandler(TransportRef(btp), result, cookie);
  882.                 end;
  883.             end;
  884.             otherwise
  885.                 ;
  886.         end;
  887.     end;
  888.  
  889.     function ValidTransport(tref:TransportRef): Boolean;
  890.         var
  891.             this:TransportRecordPtr;
  892.     begin
  893.         ValidTransport := false;
  894.         this := TransportRecordPtr(transports.qHead);
  895.         while this <> nil do begin
  896.             if TransportRef(this) = tref then begin
  897.                 ValidTransport := true;
  898.                 leave;
  899.             end;
  900.             this := this^.next;
  901.         end;
  902.     end;
  903.     
  904.     procedure TransportDestroy(var tref:TransportRef);
  905.         var
  906.             btp:TransportRecordPtr;
  907.             junk:OSStatus;
  908.     begin
  909.         btp := TransportRecordPtr(tref);
  910.         if btp <> nil then begin
  911.             Assert(ValidTransport(tref));
  912.             if have_OT then begin
  913.                 if btp^.ep <> nil then begin
  914.                     junk := OTCloseProvider(btp^.ep);
  915.                 end;
  916.             end else begin
  917.                 if btp^.stream <> nil then begin
  918.                     junk := MTTCPRelease(btp^.stream);
  919.                 end;
  920.                 MDisposePtr(btp^.stream_buffer);
  921.                 TransportAbortDNR(btp^.dnr_token);
  922.             end;
  923.             MDisposeHandle(btp^.input_handle);
  924.             MDisposeHandle(btp^.output_handle);
  925.             MDisposeHandle(btp^.sending_handle);
  926.             junk:=Dequeue(QElemPtr(btp),@transports);
  927.             MDisposePtr(btp);
  928.             tref := nil;
  929.         end;
  930.     end;
  931.     
  932.     function TransportCreate(var btp:TransportRecordPtr; buffer_size:longint):OSStatus;
  933.         var
  934.             err:OSStatus;
  935.             hack_mrp: MemoryReleasedProc;
  936.     begin
  937.         hack_mrp := hack_MemoryReleasedProc;
  938.         hack_MemoryReleasedProc := nil;
  939.         buffer_size := Pin(10240, buffer_size, 64512);
  940.         btp := nil;
  941.         err := OpenTransportSystem;
  942.         if err = noErr then begin
  943.             err := MNewPtr(btp, SizeOf(TransportRecord));
  944.             if err = noErr then begin
  945.                 Enqueue(QElemPtr(btp),@transports);
  946.                 btp^.input_handle := nil;
  947.                 btp^.output_handle := nil;
  948.                 btp^.sending_handle := nil;
  949.                 if have_OT then begin
  950.                     btp^.MemoryReleasedHandler := hack_mrp;
  951.                     btp^.wake_process.highLongOfPSN := 0;
  952.                     btp^.wake_process.lowLongOfPSN := kNoProcess;
  953.                     btp^.waiting_for_connect := false;
  954.                     btp^.connect_received := false;
  955.                     btp^.accept_received := false;
  956.                     btp^.passcon_received := false;
  957.                     btp^.disconnect_received := false;
  958.                     err := CreateOTEndpoint(btp^.ep, @EventHandlerOT, btp);
  959.                     if (err = noErr) & (btp^.MemoryReleasedHandler <> nil) then begin
  960.                         err := OTAckSends(btp^.ep);
  961.                     end;
  962.                 end else begin
  963.                     btp^.dnr_token := nil;
  964.                     btp^.stream := nil;
  965.                     btp^.send_cb.ioResult := noErr;
  966.                     err := MNewPtr(btp^.stream_buffer, buffer_size);
  967.                     if err = noErr then begin
  968.                         err := MTTCPCreate(btp^.stream, btp^.stream_buffer, buffer_size);
  969.                     end;
  970.                 end;
  971.                 btp^.started_opening := false;
  972.                 btp^.handle_receives := false;
  973.                 btp^.handle_sends := false;
  974.                 btp^.do_send_close := false;
  975.                 btp^.send_error := noErr;
  976.                 btp^.open_result := inProgress;
  977.                 btp^.tstate := T_Bored;
  978.                 btp^.receive_error := noErr;
  979.                 if err <> noErr then begin
  980.                     TransportDestroy(TransportRef(btp));
  981.                 end;
  982.             end;
  983.         end;
  984.         TransportCreate := err;
  985.     end;
  986.     
  987.     function TransportHandleReceives(tref:TransportRef): OSStatus;
  988.         var
  989.             err, junk: OSStatus;
  990.             btp:TransportRecordPtr;
  991.     begin
  992.         btp := TransportRecordPtr(tref);
  993.         Assert(btp <> nil);
  994.         Assert(ValidTransport(tref));
  995.         err := noErr;
  996.         if not btp^.handle_receives then begin
  997.             junk := GetCurrentProcess(btp^.wake_process);
  998.             err := MNewHandle(btp^.input_handle, 0);
  999.             btp^.handle_receives := err = noErr;            
  1000.         end;
  1001.         TransportHandleReceives := err;
  1002.     end;
  1003.     
  1004.     function TransportHandleSends(tref:TransportRef): OSStatus;
  1005.         var
  1006.             err, err2: OSStatus;
  1007.             btp:TransportRecordPtr;
  1008.     begin
  1009.         btp := TransportRecordPtr(tref);
  1010.         Assert(btp <> nil);
  1011.         Assert(ValidTransport(tref));
  1012.         err := noErr;
  1013.         if not btp^.handle_sends then begin
  1014.             err := MNewHandle(btp^.output_handle, 0);
  1015.             err2 := MNewHandle(btp^.sending_handle, 0);
  1016.             if err = noErr then begin
  1017.                 err := err2;
  1018.             end;
  1019.             btp^.handle_sends := err = noErr;
  1020.         end;
  1021.         TransportHandleSends := err;
  1022.     end;
  1023.     
  1024.     function TransportHandleTransfers(tref:TransportRef): OSStatus;
  1025.         var
  1026.             err: OSStatus;
  1027.     begin
  1028.         err := TransportHandleReceives(tref);
  1029.         if err = noErr then begin
  1030.             err :=TransportHandleSends(tref);
  1031.         end;
  1032.         TransportHandleTransfers := err;
  1033.     end;
  1034.     
  1035.     function TransportOpenActiveConnection(var tref:TransportRef; dest:Str255; localport:integer; buffer_size:longint): OSStatus;
  1036.         var
  1037.             btp:TransportRecordPtr;
  1038.             err: OSStatus;
  1039.             portstr:Str255;
  1040.             n:longint;
  1041.     begin
  1042.         err := TransportCreate(btp, buffer_size);
  1043.         if err = noErr then begin
  1044.             if have_OT then begin
  1045.                 err := BindOTListener(btp^.ep, localport, 0);
  1046.                 if err = noErr then begin
  1047.                     err:=OTSetAsynchronous(btp^.ep);
  1048.                 end;
  1049.                 if err = noErr then begin
  1050.                     MZero(@btp^.rcvCall, sizeof(btp^.rcvCall));
  1051.                     OTInitNetbuf(btp^.rcvCall.addr, @btp^.rcvsin, sizeof(InetAddress));
  1052.         
  1053.                     MZero(@btp^.sndCall, sizeof(btp^.sndCall));
  1054.                     P2C(@dest);
  1055.                     OTInitNetbuf(btp^.sndCall.addr, @btp^.sndsin, OTInitDNSAddress(btp^.sndsin, @dest));
  1056.                     
  1057.                     err := OTConnect(btp^.ep, btp^.sndCall, btp^.rcvCall);
  1058.                     if err = kOTNoDataErr then begin
  1059.                         err := noErr;
  1060.                     end;
  1061.                 end;
  1062.             end else begin
  1063.                 SplitBy (dest, ':', dest, portstr);
  1064.                 StringToNum(portstr, n);
  1065.                 btp^.remote_port := n;
  1066.                 btp^.local_port := localport;
  1067.                 err := TransportNameToAddr(dest, btp^.dnr_token);
  1068.             end;
  1069.             btp^.started_opening := true;
  1070.             if err <> noErr then begin
  1071.                 TransportDestroy(TransportRef(btp));
  1072.             end;
  1073.         end;
  1074.         tref := TransportRef(btp);
  1075.         TransportOpenActiveConnection := err;
  1076.     end;
  1077.  
  1078.     function TransportOpenPassiveConnection(var tref:TransportRef; var localport:integer; buffer_size:longint): OSStatus;
  1079.         var
  1080.             btp:TransportRecordPtr;
  1081.             err:OSStatus;
  1082.     begin
  1083.         err := TransportCreate(btp, buffer_size);
  1084.         if err = noErr then begin
  1085.             if have_OT then begin
  1086.                 btp^.waiting_for_connect := true;
  1087.                 err := BindOTListener(btp^.ep, localport, 1);
  1088.             end else begin
  1089.                 err := MTTCPPassiveOpen(btp^.open_cb, btp^.stream, localport);
  1090.             end;
  1091.             btp^.started_opening := true;
  1092.             if err <> noErr then begin
  1093.                 TransportDestroy(TransportRef(btp));
  1094.             end;
  1095.         end;
  1096.         tref := TransportRef(btp);
  1097.         TransportOpenPassiveConnection := err;
  1098.     end;
  1099.     
  1100.     procedure TransportGetOpenResult(tref:TransportRef; var result: OSStatus);
  1101.         var
  1102.             btp:TransportRecordPtr;
  1103.     begin
  1104.         btp := TransportRecordPtr(tref);
  1105.         Assert(btp <> nil);
  1106.         Assert(ValidTransport(tref));
  1107.         result := btp^.open_result
  1108.     end;
  1109.     
  1110.     procedure ProcessOpen(btp:TransportRecordPtr);
  1111.         var
  1112.             addr:IPAddr;
  1113.             result: OSStatus;
  1114.     begin
  1115.         Assert(btp <> nil);
  1116.         if btp^.started_opening & (btp^.open_result = inProgress) then begin
  1117.             if have_OT then begin
  1118.                 if btp^.waiting_for_connect then begin
  1119.                     MZero(@btp^.rcvCall, sizeof(btp^.rcvCall));
  1120.                     OTInitNetbuf(btp^.rcvCall.addr, @btp^.rcvsin, sizeof(InetAddress));
  1121.                     result := OTListen(btp^.ep, btp^.rcvCall);
  1122.                     if result = kOTNoDataErr then begin
  1123.                         result := inProgress;
  1124.                     end else begin
  1125.                         btp^.waiting_for_connect := false;
  1126.                         if result = noErr then begin
  1127.                             result := OTAccept(btp^.ep, btp^.ep, btp^.rcvCall);
  1128.                         end;
  1129.                     end;
  1130.                 end else if btp^.disconnect_received then begin
  1131.                     result := -71;
  1132.                 end else if btp^.connect_received then begin
  1133.                     result := btp^.connect_result;
  1134.                 end else if btp^.accept_received then begin
  1135.                     result := btp^.accept_result;
  1136.                 end else if btp^.passcon_received then begin
  1137.                     result := btp^.passcon_result;
  1138.                 end else begin
  1139.                     result := inProgress;
  1140.                 end;
  1141.             end else begin
  1142.                 result := noErr;
  1143.                 if btp^.dnr_token <> nil then begin
  1144.                     TransportGetNameToAddrResult(btp^.dnr_token, result, nil, @addr, 1);
  1145.                     if result = noErr then begin
  1146.                         result := MTTCPActiveOpen(btp^.open_cb, btp^.stream, btp^.local_port, addr, btp^.remote_port);
  1147.                     end;
  1148.                 end;
  1149.                 if result = noErr then begin
  1150.                     result := btp^.open_cb.ioResult;
  1151.                 end;
  1152.             end;
  1153.             btp^.open_result := result;
  1154.         end;
  1155.     end;
  1156.  
  1157.     procedure IdleReceive(btp:TransportRecordPtr);
  1158.         var
  1159.             err: OSStatus;
  1160.             result: OTResult;
  1161.             flags:OTFlags;
  1162.             cb:TCPControlBlock;
  1163.             len, count: longint;
  1164.             space: packed array[1..2048] of byte;
  1165.     begin
  1166.         if btp^.handle_receives then begin
  1167.             len := GetHandleSize(btp^.input_handle);
  1168.             if have_OT then begin
  1169.                 if len < 10240 then begin
  1170.                     result := OTRcv(btp^.ep, @space, SizeOf(space), flags);
  1171.                     if result >= 0 then begin
  1172.                         err := PtrAndHand(@space, btp^.input_handle, result);
  1173.                     end else begin
  1174.                         if (result <> kOTNoDataErr) & (result <> kOTOutStateErr) then begin
  1175.                             err := result;
  1176.                         end else begin
  1177.                             err := noErr;
  1178.                         end;
  1179.                     end;
  1180.                     if err <> noErr then begin
  1181.                         btp^.receive_error := err;
  1182.                     end;
  1183.                 end;
  1184.             end else begin
  1185.                 MTZeroTCPCB(cb, btp^.stream, TCPcsStatus);
  1186.                 err := PBControlSync(@cb);
  1187.                 if err = noErr then begin
  1188.                     count := Min(cb.status.amtUnreadData, 10240 - len);
  1189.                     if count > 0 then begin
  1190.                         err := MSetHandleSize(btp^.input_handle, len + count);
  1191.                         if err = noErr then begin
  1192.                             HLock(btp^.input_handle);
  1193.                             MTZeroTCPCB(cb, btp^.stream, TCPcsRcv);
  1194.                             cb.receive.rcvBuff := btp^.input_handle^;
  1195.                             cb.receive.rcvBuffLength := count;
  1196.                             err := PBControlSync(@cb);
  1197.                             count := cb.receive.rcvBuffLength;
  1198.                             HUnlock(btp^.input_handle);
  1199.                         end;
  1200.                         if err <> noErr then begin
  1201.                             count := 0;
  1202.                             btp^.receive_error := err;
  1203.                         end;
  1204.                         SetHandleSize(btp^.input_handle, len + count);
  1205.                     end;
  1206.                 end;
  1207.             end;
  1208.         end;
  1209.     end;
  1210.     
  1211.     function TransportCharsAvailable(tref:TransportRef): longint;
  1212.         var
  1213.             btp:TransportRecordPtr;
  1214.     begin
  1215.         btp := TransportRecordPtr(tref);
  1216.         Assert(btp <> nil);
  1217.         Assert(ValidTransport(tref));
  1218.         Assert(btp^.handle_receives);
  1219.         TransportCharsAvailable := GetHandleSize(btp^.input_handle);
  1220.     end;
  1221.     
  1222.     function TransportReceive(tref:TransportRef; buf: Ptr; len:longint; var count:longint): OSStatus;
  1223.         var
  1224.             btp:TransportRecordPtr;
  1225.             err: OSStatus;
  1226.     begin
  1227.         btp := TransportRecordPtr(tref);
  1228.         Assert(btp <> nil);
  1229.         Assert(ValidTransport(tref));
  1230.         Assert(btp^.handle_receives);
  1231.         if btp^.receive_error <> noErr then begin
  1232.             err := btp^.receive_error;
  1233.             btp^.receive_error := noErr;
  1234.             count := 0;
  1235.         end else begin
  1236.             err := noErr;
  1237.             count := Min(len, GetHandleSize(btp^.input_handle));
  1238.             if count > 0 then begin
  1239.                 BlockMoveData(btp^.input_handle^, buf, count);
  1240.                 MMungerDelete(btp^.input_handle, 0, count);
  1241.             end;
  1242.         end;
  1243.         TransportReceive := err;
  1244.     end;
  1245.     
  1246.     function TransportSend(tref:TransportRef; buf: Ptr; len:longint): OSStatus;
  1247.         var
  1248.             btp:TransportRecordPtr;
  1249.             err: OSStatus;
  1250.     begin
  1251.         btp := TransportRecordPtr(tref);
  1252.         Assert(btp <> nil);
  1253.         Assert(ValidTransport(tref));
  1254.         if not btp^.handle_sends then begin
  1255.             err := -31; { I'd like to know why this actually occurs }
  1256.         end else begin
  1257.             err := PtrAndHand(buf, btp^.output_handle, len);
  1258.             if err = noErr then begin
  1259.                 err := btp^.send_error;
  1260.                 btp^.send_error:= noErr;
  1261.             end;
  1262.         end;
  1263.         TransportSend := err;
  1264.     end;
  1265.     
  1266.     procedure IdleSend(btp: TransportRecordPtr);
  1267.         procedure SwapHandles(var h1, h2:Handle);
  1268.             var
  1269.                 tmph:Handle;
  1270.         begin
  1271.             tmph := h1;
  1272.             h1 := h2;
  1273.             h2 := tmph;
  1274.         end;
  1275.         var
  1276.             err: OSStatus;
  1277.             result: OTResult;
  1278.             len:longint;
  1279.     begin
  1280.         if btp^.handle_sends then begin
  1281.             len := GetHandleSize(btp^.output_handle);
  1282.             if btp^.do_send_close & (len = 0) then begin
  1283.                 btp^.handle_sends := false;
  1284.                 TransportSendClose(TransportRef(btp));
  1285.             end else begin
  1286.                 if have_OT then begin
  1287.                     if len > 0 then begin
  1288.                         HLock(btp^.output_handle);
  1289.                         result := OTSnd(btp^.ep, btp^.output_handle^, len, 0);
  1290.                         HUnlock(btp^.output_handle);
  1291.                         if result >= 0 then begin
  1292.                             MMungerDelete(btp^.output_handle, 0, result);
  1293.                         end else if result <> kOTFlowErr then begin
  1294.                             btp^.send_error := result;
  1295.                             SetHandleSize(btp^.output_handle, 0);
  1296.                         end;
  1297.                     end;
  1298.                 end else begin
  1299.                     if btp^.send_cb.ioResult <> inProgress then begin
  1300.                         HUnlock(btp^.sending_handle);
  1301.                         SetHandleSize(btp^.sending_handle, 0);
  1302.                         if btp^.send_cb.ioResult <> noErr then begin
  1303.                             btp^.send_error := btp^.send_cb.ioResult;
  1304.                             btp^.send_cb.ioResult := noErr;
  1305.                         end;
  1306.                         if len > 0 then begin
  1307.                             SwapHandles(btp^.output_handle, btp^.sending_handle);
  1308.                             HLock(btp^.sending_handle);
  1309.                             btp^.send_wds.buffer := btp^.sending_handle^;
  1310.                             btp^.send_wds.size := len;
  1311.                             btp^.send_wds.term := 0;
  1312.                             MTZeroTCPCB(btp^.send_cb, btp^.stream, TCPcsSend);
  1313.                             btp^.send_cb.send.wds := @btp^.send_wds;
  1314.                             btp^.send_cb.send.pushFlag := 1;
  1315.                             err := PBControlAsync(@btp^.send_cb);
  1316.                         end;
  1317.                     end;
  1318.                 end;
  1319.             end;
  1320.         end;
  1321.     end;
  1322.  
  1323.     procedure TransportSendClose(tref:TransportRef);
  1324.         var
  1325.             btp:TransportRecordPtr;
  1326.             err: OSStatus;
  1327.     begin
  1328.         btp := TransportRecordPtr(tref);
  1329.         Assert(btp <> nil);
  1330.         Assert(ValidTransport(tref));
  1331.         if btp^.handle_sends then begin
  1332.             btp^.do_send_close := true;
  1333.             IdleSend(btp);
  1334.         end else begin
  1335.             if have_OT then begin
  1336.                 err := OTSndOrderlyDisconnect(btp^.ep);
  1337.             end else begin
  1338.                 err := MTTCPClose(btp^.close_cb, btp^.stream);
  1339.             end;
  1340.         end;
  1341.     end;
  1342.     
  1343.     function TransportGetConnectionStateInteruptSafe (tref:TransportRef): TCPStateType; { * }
  1344.         var
  1345.             btp:TransportRecordPtr;
  1346.             state:TCPStateType;
  1347.     begin
  1348.         btp := TransportRecordPtr(tref);
  1349.         if btp = nil then begin
  1350.             state := T_Dead;
  1351.         end else if have_OT then begin
  1352.             state := TransportGetConnectionStateOT(btp^.ep);
  1353.         end else begin
  1354.             state := btp^.tstate;
  1355.         end;
  1356.         TransportGetConnectionStateInteruptSafe := state;
  1357.     end;
  1358.  
  1359.     procedure IdleMacTCPConnectionState(btp:TransportRecordPtr);
  1360.     begin
  1361.         Assert(not have_OT);
  1362.         if btp^.dnr_token <> nil then begin
  1363.             btp^.tstate := T_Opening;
  1364.         end else if btp^.stream = nil then begin
  1365.             btp^.tstate := T_Dead;
  1366.         end else begin
  1367.             btp^.tstate := MTTCPState(btp^.stream);
  1368.         end;
  1369.     end;
  1370.     
  1371.     function TransportGetConnectionState (tref:TransportRef): TCPStateType;
  1372.         var
  1373.             btp:TransportRecordPtr;
  1374.             state:TCPStateType;
  1375.     begin
  1376.         btp := TransportRecordPtr(tref);
  1377.         if btp = nil then begin
  1378.             state := T_Dead;
  1379.         end else if have_OT then begin
  1380.             state := TransportGetConnectionStateOT(btp^.ep);
  1381.         end else begin
  1382.             btp^.tstate := MTTCPState(btp^.stream);
  1383.             state := btp^.tstate;
  1384.         end;
  1385.         TransportGetConnectionState := state;
  1386.     end;
  1387.     
  1388.     procedure TransportLowGetStreamPtr(tref:TransportRef; var stream: StreamPtr);
  1389.         var
  1390.             btp:TransportRecordPtr;
  1391.     begin
  1392.         btp := TransportRecordPtr(tref);
  1393.         Assert(btp <> nil);
  1394.         Assert(ValidTransport(tref));
  1395.         Assert(not have_OT);
  1396.         stream := btp^.stream;
  1397.     end;
  1398.     
  1399.     procedure TransportLowGetEndpointRef(tref:TransportRef; var ep: EndpointRef);
  1400.         var
  1401.             btp:TransportRecordPtr;
  1402.     begin
  1403.         btp := TransportRecordPtr(tref);
  1404.         Assert(btp <> nil);
  1405.         Assert(have_OT);
  1406.         Assert(ValidTransport(tref));
  1407.         ep := btp^.ep;
  1408.     end;
  1409.  
  1410.     function TransportLowSetOTAckSends(tref:TransportRef; handler: MemoryReleasedProc): OSStatus;
  1411.         var
  1412.             err: OSStatus;
  1413.             btp:TransportRecordPtr;
  1414.     begin
  1415.         btp := TransportRecordPtr(tref);
  1416.         Assert(btp <> nil);
  1417.         Assert(ValidTransport(tref));
  1418.         Assert(have_OT);
  1419.         err := noErr;
  1420.         if btp^.MemoryReleasedHandler = nil then begin
  1421.             err := OTAckSends(btp^.ep);
  1422.         end;
  1423.         if err = noErr then begin
  1424.             btp^.MemoryReleasedHandler := handler;
  1425.         end;
  1426.         TransportLowSetOTAckSends := err;
  1427.     end;
  1428.  
  1429.     function TransportGetPorts(tref:TransportRef; var localip: IPAddr; var localport: integer; var remoteip: longint; var remoteport: integer): OSStatus;
  1430.         var
  1431.             err: OSStatus;
  1432.             btp: TransportRecordPtr;
  1433.             cb: TCPControlBlock;
  1434.             localBind, remoteBind: TBind;
  1435.             localAddr, remoteAddr: InetAddress;
  1436.     begin
  1437.         btp := TransportRecordPtr(tref);
  1438.         Assert(btp <> nil);
  1439.         Assert(ValidTransport(tref));
  1440.         localip := 0;
  1441.         localport := 0;
  1442.         remoteip := 0;
  1443.         remoteport := 0;
  1444.         if have_OT then begin
  1445.             btp^.getprotaddr_result := inProgress;
  1446.             OTInitNetbuf(localBind.addr, @localAddr, SizeOf(localAddr));
  1447.             OTInitNetbuf(remoteBind.addr, @remoteAddr, SizeOf(remoteAddr));
  1448.             err := OTGetProtAddress(btp^.ep, localBind, remoteBind);
  1449.             if err = noErr then begin
  1450.                 while btp^.getprotaddr_result = inProgress do begin
  1451.                     OTIdle;
  1452.                 end;
  1453.                 err := btp^.getprotaddr_result;
  1454.             end;
  1455.             if err = noErr then begin
  1456.                 localip := localAddr.fHost;
  1457.                 localport := localAddr.fPort;
  1458.                 remoteip := remoteAddr.fHost;
  1459.                 remoteport := remoteAddr.fPort;
  1460.             end;
  1461.         end else begin
  1462.             MTZeroTCPCB(cb, btp^.stream, TCPcsStatus);
  1463.             err := PBControlSync(@cb);
  1464.             if err = noErr then begin
  1465.                 localip := cb.status.localhost;
  1466.                 localport := cb.status.localport;
  1467.                 remoteip := cb.status.remotehost;
  1468.                 remoteport := cb.status.remoteport;
  1469.             end;
  1470.         end;
  1471.         TransportGetPorts := err;
  1472.     end;
  1473.     
  1474.     const
  1475.         max_tcp_listeners = 20;
  1476.     
  1477.     type
  1478.         OTSequenceArray = array[0..0] of OTSequence;
  1479.         OTSequenceArrayPtr = ^OTSequenceArray;
  1480.         OTSequenceArrayHandle = ^OTSequenceArrayPtr;
  1481.     
  1482.     type
  1483.         TransportListenRecord = record
  1484.             case boolean of
  1485.             false:(
  1486.                 mt_buffer_size:longint;
  1487.                 mt_listeners_count:integer;
  1488.                 mt_listeners:array[1..max_tcp_listeners] of TransportRef;
  1489.                 localport:integer;
  1490.             )
  1491.             true:(
  1492.                 ep: EndpointRef;
  1493.                 sequences: OTSequenceArrayHandle;
  1494.             )
  1495.         end;
  1496.         TransportListenRecordPtr = ^TransportListenRecord;
  1497.  
  1498.     function TransportListen(var token:Ptr; localport:integer; listeners:integer; buffer_size:longint):OSStatus;
  1499.         var
  1500.             lp:TransportListenRecordPtr;
  1501.             err, junk:OSStatus;
  1502.             i:integer;
  1503.     begin
  1504.         lp := nil;
  1505.         err := OpenTransportSystem;
  1506.         if err = noErr then begin
  1507.             err := MNewPtr(lp, SizeOf(TransportListenRecord));
  1508.             if err = noErr then begin
  1509.                 if have_OT then begin
  1510.                     err := MNewHandle(lp^.sequences, 0);
  1511.                     if err = noErr then begin
  1512.                         err := CreateOTEndpoint(lp^.ep, nil, lp);
  1513.                         if err = noErr then begin
  1514.                             err := BindOTListener(lp^.ep, localport, 99);
  1515.                             if err <> noErr then begin
  1516.                                 junk := OTCloseProvider(lp^.ep);
  1517.                             end;
  1518.                         end;
  1519.                         if err <> noErr then begin
  1520.                             MDisposeHandle(lp^.sequences);
  1521.                         end;
  1522.                     end;
  1523.                 end else begin
  1524.                     lp^.localport := localport;
  1525.                     lp^.mt_listeners_count := listeners;
  1526.                     lp^.mt_buffer_size := buffer_size;
  1527.                     for i := 1 to lp^.mt_listeners_count do begin
  1528.                         lp^.mt_listeners[i] := nil;
  1529.                     end;
  1530.                 end;
  1531.             end;
  1532.         end;
  1533.         if err <> noErr then begin
  1534.             MDisposePtr(lp);
  1535.         end;
  1536.         token := Ptr(lp);
  1537.         TransportListen := err;
  1538.     end;
  1539.         
  1540.     function TransportGetListenerConnectionOT(lp:TransportListenRecordPtr; var tref:TransportRef):OSStatus;
  1541.         function CountSequences: longint;
  1542.         begin
  1543.             CountSequences := GetHandleSize(Handle(lp^.sequences)) div SizeOf(OTSequence);
  1544.         end;
  1545.         
  1546.         procedure DelSequence(sequence: OTSequence);
  1547.             var
  1548.                 i: longint;
  1549.         begin
  1550.             for i := 0 to CountSequences - 1 do begin
  1551.                 if lp^.sequences^^[i] = sequence then begin
  1552.                     MMUngerDelete(Handle(lp^.sequences), i * SizeOf(OTSequence), SizeOf(OTSequence));
  1553.                     leave;
  1554.                 end;
  1555.             end;
  1556.         end;
  1557.         label
  1558.             1;
  1559.         var
  1560.             err: OSStatus;
  1561.             result: OTResult;
  1562.             rcvCall:TCall;
  1563.             rcvsin:InetAddress;
  1564.             btp:TransportRecordPtr;
  1565.             discon: TDiscon;
  1566.             sequence: OTSequence;
  1567.     begin
  1568.         1:
  1569.         repeat
  1570.             MZero(@rcvCall, sizeof(rcvCall));
  1571.             OTInitNetbuf(rcvCall.addr, @rcvsin, sizeof(InetAddress));
  1572.             result := OTListen(lp^.ep, rcvCall);
  1573.             if result = noErr then begin
  1574.                 sequence := rcvCall.sequence;
  1575.                 result := PtrAndHand(@sequence, Handle(lp^.sequences), SizeOf(sequence));
  1576.             end else if result = kOTLookErr then begin
  1577.                 MZero(@discon, sizeof(discon));
  1578.                 result := OTRcvDisconnect(lp^.ep, @discon);
  1579.                 if result = noErr then begin
  1580.                     DelSequence(discon.sequence);
  1581.                 end;
  1582.             end;
  1583.         until result <> noErr;
  1584.         if result <> kOTNoDataErr then begin
  1585.             err := result;
  1586.         end else begin
  1587.             if CountSequences = 0 then begin
  1588.                 err := inProgress;
  1589.             end else begin
  1590.                 err := TransportCreate(btp, 0);
  1591.                 if err = noErr then begin
  1592.                     tref := TransportRef(btp);
  1593.                     btp^.started_opening := true;
  1594.                     MZero(@rcvCall, sizeof(rcvCall));
  1595.                     rcvCall.sequence := lp^.sequences^^[0];
  1596.                     err := OTAccept(lp^.ep, btp^.ep, rcvCall);
  1597.                     if err = kOTLookErr then begin
  1598.                         TransportDestroy(tref);
  1599.                         goto 1;
  1600.                     end else begin
  1601.                         MMungerDelete(Handle(lp^.sequences), 0, SizeOf(OTSequence));
  1602.                     end;
  1603.                     if err = noErr then begin
  1604.                         err:=OTSetAsynchronous(btp^.ep);
  1605.                     end;
  1606.                     if err <> noErr then begin
  1607.                         TransportDestroy(tref);
  1608.                     end;
  1609.                 end;
  1610.             end;
  1611.         end;
  1612.         TransportGetListenerConnectionOT := err;
  1613.     end;
  1614.     
  1615.     function TransportGetListenerConnection(token:Ptr; var tref:TransportRef):OSStatus;
  1616.         var
  1617.             err, result:OSStatus;
  1618.             lp:TransportListenRecordPtr;
  1619.             i:integer;
  1620.     begin
  1621.         lp := TransportListenRecordPtr(token);
  1622.         if lp = nil then begin
  1623.             err := -28;
  1624.         end else begin
  1625.             err := inProgress;
  1626.             if have_OT then begin
  1627.                 err := TransportGetListenerConnectionOT(lp, tref);
  1628.             end else begin
  1629.                 for i := 1 to lp^.mt_listeners_count do begin
  1630.                     if (lp^.mt_listeners[i] = nil) & EnoughSpace(100000, 70000) then begin
  1631.                         err := TransportOpenPassiveConnection(lp^.mt_listeners[i], lp^.localport, lp^.mt_buffer_size);
  1632.                         leave; { only create one listener, that allows the listeners to be shared a bit better }
  1633.                     end;
  1634.                 end;
  1635.  
  1636.                 err := inProgress;
  1637.                 for i := 1 to lp^.mt_listeners_count do begin
  1638.                     if (lp^.mt_listeners[i] <> nil) then begin
  1639.                         Assert(ValidTransport(lp^.mt_listeners[i]));
  1640.                         TransportGetOpenResult(lp^.mt_listeners[i], result);
  1641.                         case result of
  1642.                             inProgress: begin
  1643.                             end;
  1644.                             noErr:begin
  1645.                                 tref := lp^.mt_listeners[i];
  1646.                                 lp^.mt_listeners[i] := nil;
  1647.                                 err := noErr;
  1648.                                 leave;
  1649.                             end;
  1650.                             otherwise begin
  1651.                                 TransportDestroy(lp^.mt_listeners[i]);
  1652.                             end;
  1653.                         end;
  1654.                     end;
  1655.                 end;
  1656.             end;
  1657.         end;
  1658.         if err <> noErr then begin
  1659.             tref := nil;
  1660.         end;
  1661.         TransportGetListenerConnection := err;
  1662.     end;
  1663.     
  1664.     procedure TransportDestroyListener(var token:Ptr);
  1665.         var
  1666.             junk:OSStatus;
  1667.             lp:TransportListenRecordPtr;
  1668.             i:integer;
  1669.     begin
  1670.         lp := TransportListenRecordPtr(token);
  1671.         if lp <> nil then begin
  1672.             if have_OT then begin
  1673.                 junk := OTCloseProvider(lp^.ep);
  1674.                 MDisposeHandle(lp^.sequences);
  1675.             end else begin
  1676.                 for i := 1 to lp^.mt_listeners_count do begin
  1677.                     TransportDestroy(lp^.mt_listeners[i]);
  1678.                 end;
  1679.                 lp^.mt_listeners_count := 0;
  1680.             end;
  1681.             MDisposePtr(token);
  1682.         end;
  1683.     end;
  1684.  
  1685.     function CreateOTUDPEndpoint(var ep:EndpointRef; proc:OTNotifyProcPtr; var localport: integer; context:univ Ptr):OSErr;
  1686.         var
  1687.             err, junk: OSStatus;
  1688.             config: Str255;
  1689.             info: TEndpointInfo;
  1690.             reqsin, retsin:InetAddress;
  1691.             req, ret:TBind;
  1692.     begin
  1693.         config := 'udp';
  1694.         P2C(@config);
  1695.         ep:=OTOpenEndpoint(OTCreateConfiguration(@config),0,info,err);
  1696.         if (err = noErr) & (proc <> nil) then begin
  1697.             err:=OTInstallNotifier(ep, proc, context);
  1698.         end;
  1699.  
  1700.         if err = noErr then begin
  1701.             if localport <> 0 then begin
  1702.                 OTInitInetAddress(reqsin, localport, 0);
  1703.                 OTInitNetbuf(req.addr, @reqsin, sizeof(InetAddress));
  1704.             end else begin
  1705.                 OTInitNetbuf(req.addr, nil, 0);
  1706.             end;
  1707.             req.qlen := 1;
  1708.             
  1709.             MZero(@ret, sizeof(ret));
  1710.             OTInitNetbuf(ret.addr, @retsin, sizeof(InetAddress));
  1711.             err := OTBind(ep, @req, @ret);
  1712.             localport := retsin.fPort;
  1713.         end;
  1714.         if (err = noErr) & (localport <> 0) & (localport <> retsin.fPort) then begin
  1715.             err := couldNotGetRequestedPortErr;
  1716.         end;
  1717.         if err = noErr then begin
  1718.             err:=OTSetNonBlocking(ep);
  1719.         end;
  1720.         if err <> noErr then begin
  1721.             junk := OTCloseProvider(ep);
  1722.         end;
  1723.         CreateOTUDPEndpoint := err;
  1724.     end;
  1725.     
  1726.     procedure UDPEventHandlerOT (tup: TransportUDPRecordPtr; event: OTEventCode; result: OTResult; cookie: univ Ptr);
  1727.     begin
  1728.         cookie := cookie; { UNUSED! }
  1729.         result := result; { Unused! }
  1730.         case event of
  1731.             T_DATA: begin
  1732.                 Inc(tup^.received_packets);
  1733.             end;
  1734.             otherwise
  1735.                 ;
  1736.         end;
  1737.     end;
  1738.  
  1739.     function TransportUDPOpenPort(var tref: TransportUDPRef; var localport: integer; buffer_size:longint): OSStatus;
  1740.         var
  1741.             err:OSStatus;
  1742.             tup: TransportUDPRecordPtr;
  1743.     begin
  1744.         buffer_size := Pin(10240, buffer_size, 64512);
  1745.         tup := nil;
  1746.         err := OpenTransportSystem;
  1747.         if err = noErr then begin
  1748.             err := MNewPtr(tup, SizeOf(TransportUDPRecord));
  1749.             if err = noErr then begin
  1750.                 if have_OT then begin
  1751.                     tup^.received_packets := 0;
  1752.                     tup^.read_packets := 0;
  1753.                     err := CreateOTUDPEndpoint(tup^.ep, @UDPEventHandlerOT, localport, tup);
  1754.                 end else begin
  1755.                     tup^.stream := nil;
  1756.                     err := MNewPtr(tup^.stream_buffer, buffer_size);
  1757.                     if err = noErr then begin
  1758.                         err := MTUDPCreate(tup^.stream, localport, @tup^.outstanding_packets, tup^.stream_buffer, buffer_size);
  1759.                     end;
  1760.                 end;
  1761.                 if err <> noErr then begin
  1762.                     TransportUDPDestroy(TransportUDPRef(tup));
  1763.                 end;
  1764.             end;
  1765.         end;
  1766.         tref := TransportUDPRef(tup);
  1767.         TransportUDPOpenPort := err;
  1768.     end;
  1769.     
  1770.     procedure TransportUDPDestroy (var tref: TransportUDPRef);
  1771.         var
  1772.             err, junk: OSStatus;
  1773.             tup: TransportUDPRecordPtr;
  1774.     begin
  1775.         err := noErr;
  1776.         tup := TransportUDPRecordPtr(tref);
  1777.         if tup <> nil then begin
  1778.             if have_OT then begin
  1779.                 if tup^.ep <> nil then begin
  1780.                     junk := OTCloseProvider(tup^.ep);
  1781.                 end;
  1782.             end else begin
  1783.                 if tup^.stream <> nil then begin
  1784.                     err := MTUDPRelease(tup^.stream);
  1785.                 end;
  1786.                 MDisposePtr(tup^.stream_buffer);
  1787.             end;
  1788.             MDisposePtr(tup);
  1789.             tref := nil;
  1790.         end;
  1791.     end;
  1792.     
  1793.     const
  1794.         max_udp_datalen = 2048;
  1795.         
  1796.     function TransportUDPDatagramsAvailable (tref: TransportUDPRef): longint;
  1797.         var
  1798.             tup: TransportUDPRecordPtr;
  1799.     begin
  1800.         tup := TransportUDPRecordPtr(tref);
  1801.         Assert(tup <> nil);
  1802.         if have_OT then begin
  1803.             TransportUDPDatagramsAvailable := tup^.received_packets - tup^.read_packets;
  1804.         end else begin
  1805.             TransportUDPDatagramsAvailable := tup^.outstanding_packets;
  1806.         end;
  1807.     end;
  1808.  
  1809.     function TransportUDPRead (tref: TransportUDPRef; var remoteIP: longint; var remoteport: integer;
  1810.                                     var datap: ptr; var datalen: integer): OSStatus;
  1811.         var
  1812.             err:OSStatus;
  1813.             tup: TransportUDPRecordPtr;
  1814.             udata:TUnitData;
  1815.             flags: OTFlags;
  1816.             srcsin: InetAddress;
  1817.             tmp_packets: longint;
  1818.     begin
  1819.         tup := TransportUDPRecordPtr(tref);
  1820.         Assert(tup <> nil);
  1821.         if have_OT then begin
  1822.             err := MNewPtr(datap, max_udp_datalen);
  1823.             if err = noErr then begin
  1824.                 MZero(@udata, SizeOf(udata));
  1825.                 OTInitNetbuf(udata.addr, @srcsin, SizeOf(srcsin));
  1826.                 OTInitNetbuf(udata.udata, datap, max_udp_datalen);
  1827.                 tmp_packets := tup^.received_packets;
  1828.                 err := OTRcvUData(tup^.ep,udata, flags);
  1829.                 if err = noErr then begin
  1830.                     Inc(tup^.read_packets);
  1831.                     datalen := udata.udata.len;
  1832.                     remoteIP := srcsin.fHost;
  1833.                     remoteport := srcsin.fPort;
  1834.                 end;
  1835.                 if (err = kOTNoDataErr) then begin
  1836.                     tup^.read_packets := tmp_packets;
  1837.                 end;
  1838.             end;
  1839.             if err <> noErr then begin
  1840.                 MDisposePtr(datap);
  1841.             end;
  1842.         end else begin
  1843.             err := MTUDPRead(tup^.stream, @tup^.outstanding_packets, remoteIP, remoteport, datap, datalen);
  1844.         end;
  1845.         TransportUDPRead := err;
  1846.     end;
  1847.  
  1848.     function TransportUDPReturnBuffer (tref: TransportUDPRef; datap: ptr): OSStatus;
  1849.         var
  1850.             err:OSStatus;
  1851.             tup: TransportUDPRecordPtr;
  1852.     begin
  1853.         err := noErr;
  1854.         tup := TransportUDPRecordPtr(tref);
  1855.         Assert(tup <> nil);
  1856.         if tup <> nil then begin
  1857.             if have_OT then begin
  1858.                 MDisposePtr(datap);
  1859.             end else begin
  1860.                 err := MTUDPReturnBuffer(tup^.stream, datap);
  1861.             end;
  1862.         end;
  1863.         TransportUDPReturnBuffer := err;
  1864.     end;
  1865.  
  1866.     function TransportUDPWrite (tref: TransportUDPRef; remoteIP: longint; remoteport: integer;
  1867.                                     datap: ptr; datalen: integer; checksum: boolean): OSStatus;
  1868.         var
  1869.             err:OSStatus;
  1870.             tup: TransportUDPRecordPtr;
  1871.             udata:TUnitData;
  1872.             destsin: InetAddress;
  1873.     begin
  1874.         err := noErr;
  1875.         tup := TransportUDPRecordPtr(tref);
  1876.         Assert(tup <> nil);
  1877.         if tup <> nil then begin
  1878.             if have_OT then begin
  1879.                 MZero(@udata, SizeOf(udata));
  1880.                 OTInitInetAddress(destsin, remoteport, remoteIP);
  1881.                 OTInitNetbuf(udata.addr, @destsin, SizeOf(destsin));
  1882.                 OTInitNetbuf(udata.udata, datap, datalen);
  1883.                 err := OTSndUData(tup^.ep,udata);
  1884.             end else begin
  1885.                 err := MTUDPWrite(tup^.stream, remoteIP, remoteport, datap, datalen, checksum);
  1886.             end;
  1887.         end;
  1888.         TransportUDPWrite := err;
  1889.     end;
  1890.  
  1891.     procedure IdleTransports;
  1892.         var
  1893.             this, next:TransportRecordPtr;
  1894.     begin
  1895.         this := TransportRecordPtr(transports.qHead);
  1896.         while this <> nil do begin
  1897.             next := this^.next;
  1898.             ProcessOpen(this);
  1899.             if this^.open_result = noErr then begin
  1900.                 IdleSend(this);
  1901.                 IdleReceive(this);
  1902.             end;
  1903.             if not have_OT then begin
  1904.                 IdleMacTCPConnectionState(this);
  1905.             end;
  1906.             this := next;
  1907.         end;
  1908.     end;
  1909.         
  1910.     procedure IdleTransport;
  1911.     begin
  1912.         IdleDNRs;
  1913.         IdleTransports;
  1914.     end;
  1915.     
  1916.     function HasOTLib:boolean;
  1917.     begin
  1918. {$IFC GENERATINGPOWERPC}
  1919.         HasOTLib := longint(@InitOpenTransport) <> kUnresolvedCFragSymbolAddress;
  1920. {$ELSEC}
  1921.         HasOTLib := true;
  1922. {$ENDC}
  1923.     end;
  1924.  
  1925.     procedure ConfigureTransport(allow_OT: Boolean);
  1926.         var
  1927.             gv:longint;
  1928.     begin
  1929.         StartupTransport;
  1930.         if not allow_OT then begin
  1931.             have_OT := false;
  1932.         end else begin
  1933.             have_OT := (Gestalt(gestaltOpenTpt, gv) = noErr) & (BAND(gv, gestaltOpenTptPresent) <> 0) & (BAND(gv, gestaltOpenTptTCPPresent) <> 0) & HasOTLib;
  1934.         end;
  1935.     end;
  1936.     
  1937.     function InitTransport(var msg: integer):OSStatus;
  1938.     begin
  1939.         msg := msg; { Unused }
  1940.         hack_MemoryReleasedProc := nil;
  1941.         gMyDeferredTaskHandlerProc := NewProc(@MyDeferredTaskHandler, uppDeferredTaskProcInfo);
  1942.         tcp_is_open := false;
  1943.         dnrs.qHead := nil;
  1944.         dnrs.qTail := nil;
  1945.         transports.qHead := nil;
  1946.         transports.qTail := nil;
  1947.         is_ref := nil;
  1948.         InitTransport := noErr;
  1949.     end;
  1950.     
  1951.     procedure FinishTransport;
  1952.     begin
  1953.         WaitForDNRCompletions;
  1954.         CloseTransportSystem;
  1955.     end;
  1956.     
  1957.     procedure StartupTransport;
  1958.     begin
  1959.         StartupPreserveA5;
  1960.         StartupTCPUtils;
  1961.         SetStartup(InitTransport, IdleTransport, 0, FinishTransport);
  1962.     end;
  1963.     
  1964. end.
  1965.  
  1966.     procedure Blibble;
  1967.         var
  1968.             err, junk: OSStatus;
  1969.             config: Str255;
  1970.             info: TEndpointInfo;
  1971.             ep:EndpointRef;
  1972.             cfg: OTConfigurationPtr;
  1973.     begin
  1974.         err := OpenTransportSystem;
  1975.         if err = noErr then begin
  1976.             config := 'udp';
  1977.             P2C(@config);
  1978.             cfg := OTCreateConfiguration(@config);
  1979.             ep := OTOpenEndpoint(cfg,0,info,err);
  1980.             if ep <> nil then begin
  1981.                 junk := OTCloseProvider(ep);
  1982.             end;
  1983.         end;
  1984.     end;
  1985.     
  1986.  
  1987.